#pragma once

#include "Board.h"
#include "TestAssert.h"

class BoardTest
{
public:
	BoardTest(void);
	virtual ~BoardTest(void);
	void run()
	{
		setSquareTest();
		std::cout << ".";
		simpleGetNeighborsInfoTest();
		std::cout << ".";
		getNeighborsInfoInnerSquaresTest();
		std::cout << ".";
		getNeighborsInfoFringySquaresTest();
		std::cout << ".";
		std::cout << std::endl;
	}
protected:
	void setSquareTest()
	{
		for (size_t column = 1; column != 20; ++column)
			for (size_t row = 1; row!= 20; ++row)
			{
				Board tmp(column, row);
				int k(0);
				for (size_t i = 0; i != column; ++i)
				{
					for (size_t j = 0; j!= row; ++j)
					{
						tmp.setSquare(i, j, k);
					}
				}
				k = 0;
				std::vector<int> const *pv = tmp.toVector();
				for (size_t i = 0; i != column * row; ++i)
				{
					HANDYTEST_ASSERT(pv->at(i) == k);
				}
			}
	}
	void simpleGetNeighborsInfoTest()
	{
		{
			Board tmp(3, 3);
			tmp.setSquare(0, 1, 1);
			tmp.setSquare(1, 1, 1);
			tmp.setSquare(2, 1, 1);
			Board::InfoType info = tmp.getNeighborsInfo(1, 1);
			HANDYTEST_ASSERT (info.at(0, 0) == 0);
			HANDYTEST_ASSERT (info.at(1, 0) == 0);
			HANDYTEST_ASSERT (info.at(2, 0) == 0);
			HANDYTEST_ASSERT (info.at(0, 1) == 1);
			HANDYTEST_ASSERT (info.at(1, 1) == 1);
			HANDYTEST_ASSERT (info.at(2, 1) == 1);
			HANDYTEST_ASSERT (info.at(0, 2) == 0);
			HANDYTEST_ASSERT (info.at(1, 2) == 0);
			HANDYTEST_ASSERT (info.at(2, 2) == 0);
		}

		{
			Board tmp(5, 5);
			tmp.setSquare(2, 0, 1);
			tmp.setSquare(2, 1, 1);
			tmp.setSquare(2, 2, 1);
			tmp.setSquare(2, 3, 1);
			tmp.setSquare(2, 4, 1);

			{
				for (size_t i = 2; i != 4; ++i)
				{
					Board::InfoType info = tmp.getNeighborsInfo(2, i);
					{
						for (int index = 0; index != 3; ++index)
						{
							HANDYTEST_ASSERT (info.at(index) == 0);
						}
						for (int index = 3; index != 6; ++index)
						{
							HANDYTEST_ASSERT (info.at(index) == 1);
						}
						for (int index = 6; index != 9; ++index)
						{
							HANDYTEST_ASSERT (info.at(index) == 0);
						}
					}
				}
			}
		}
	}

	//************************************
	// Method:    getNeighborsInfoInnerSquaresTest
	// FullName:  BoardTest::getNeighborsInfoInnerSquaresTest
	// Access:    protected 
	// Returns:   void
	// Qualifier:
	//            Test board of different size.
	//            On odd number rows, the square is 1, others are 0.
	//************************************
	void getNeighborsInfoInnerSquaresTest()
	{
		for (size_t row = 3; row != 21; row+=2)
		{
			size_t column(row);
			Board tmp(row, column);
			//Initialize board, e.g.:
			//  1 0 1 0 1
			//  0 1 0 1 0
			//  1 0 1 0 1
			//  0 1 0 1 0
			//  1 0 1 0 1
			//Hence every inner square's neighbors info will be
			//1 0 1 0 1 0 1 0 1  or
			//0 1 0 1 0 1 0 1 0
			int val(1);
			for (size_t r = 0; r != row; ++r)
			{
				for (size_t c = 0; c != column; ++c)
				{
					tmp.setSquare(r, c, val);
					if (1 == val)
						val = 0;
					else
						val = 1;
				}
			}
			for (size_t r = 1; r != row - 1; ++r)
			{
				for (size_t c = 1; c != column - 1; ++c)
				{
					Board::InfoType info(tmp.getNeighborsInfo(r, c));
					int checkVal = info.at(0);
					for (size_t i = 0; i != info.size(); ++i)
					{
						HANDYTEST_ASSERT(info.at(i) == checkVal);
						if (1 == checkVal)
							checkVal = 0;
						else
							checkVal = 1;
					}
				}
			}
		}
	}

	void getNeighborsInfoFringySquaresTest()
	{
		for (size_t row = 2; row != 20; ++row)
		{
			for (size_t column = 2; column != 20; ++column)
			{
				Board tmp(row, column);
				//Initialize squares all to 1.
				for (size_t r = 0; r != row; ++r)
				{
					for (size_t c = 0; c != column; ++c)
					{
						tmp.setSquare(r, c, 1);
					}
				}
				//Four corners tests.
				{//Left up.
					Board::InfoType info(tmp.getNeighborsInfo(0, 0));
					for (size_t n = 0; n != 9; ++n)
					{
						if (n < 4 || 6 == n)
						{
							HANDYTEST_ASSERT(info.at(n) == 0);
						}
						else
						{
							HANDYTEST_ASSERT(info.at(n) == 1);
						}
					}
				}
				{//Right up.
					Board::InfoType info(tmp.getNeighborsInfo(0, column - 1));
					for (size_t n = 0; n != 9; ++n)
					{
						if (n < 3 || 5 == n || 8 == n)
						{
							HANDYTEST_ASSERT(info.at(n) == 0);
						}
						else
						{
							HANDYTEST_ASSERT(info.at(n) == 1);
						}
					}
				}
				{//Left down.
					Board::InfoType info(tmp.getNeighborsInfo(row - 1, 0));
					for (size_t n = 0; n != 9; ++n)
					{
						if (n == 0 || n == 3 || n > 5)
						{
							HANDYTEST_ASSERT(info.at(n) == 0);
						}
						else
						{
							HANDYTEST_ASSERT(info.at(n) == 1);
						}
					}
				}
				{//Right down.
					Board::InfoType info(tmp.getNeighborsInfo(row - 1, column - 1));
					for (size_t n = 0; n != 9; ++n)
					{
						if (n == 2 || n > 4)
						{
							HANDYTEST_ASSERT(info.at(n) == 0);
						}
						else
						{
							HANDYTEST_ASSERT(info.at(n) == 1);
						}
					}
				}
			}
		}
	}
};
